/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.orogeny.actions.manifest;

import com.softwarecraftsmen.archivers.zip.zipEntryAndData.ZipEntryAndData;
import com.softwarecraftsmen.orogeny.buildEnvironments.BuildEnvironment;
import com.softwarecraftsmen.orogeny.buildLogs.BuildLog;
import static com.softwarecraftsmen.orogeny.buildLogs.Verbosity.AllDetails;
import com.softwarecraftsmen.orogeny.filing.AbsoluteFile;
import static com.softwarecraftsmen.orogeny.properties.PropertyName.SystemJavaVendor;
import static com.softwarecraftsmen.orogeny.properties.PropertyName.SystemJavaVersion;
import org.jetbrains.annotations.NotNull;

import java.io.StringWriter;
import static java.lang.String.format;
import static java.util.Locale.UK;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.Attributes.Name;
import static java.util.jar.Attributes.Name.*;
import java.util.jar.Manifest;

public class ManifestAttributesManipulator
{
	private static final Name CreatedBy = new Name("Created-By");
	private final Attributes mainAttributes;
	private final BuildLog buildLog;
	private final Manifest manifest;

	public ManifestAttributesManipulator(final @NotNull Manifest manifest, final @NotNull BuildLog buildLog)
	{
		this.manifest = manifest;
		this.mainAttributes = manifest.getMainAttributes();
		this.buildLog = buildLog;
	}

	public void ensureBasicAttributes(final @NotNull BuildEnvironment buildEnvironment)
	{
		putManifestVersionHeader();
		putCreatedBy(buildEnvironment);
		putSealed();
	}

	public void putManifestVersionHeader()
	{
		putHeaderIfItDoesNotExist(MANIFEST_VERSION, "1.0");
	}

	public void putCreatedBy(final @NotNull BuildEnvironment buildEnvironment)
	{
		putHeaderIfItDoesNotExist(CreatedBy, format(UK, "%1$s (%2$s)", SystemJavaVersion.evaluate(buildEnvironment), SystemJavaVendor.evaluate(buildEnvironment)));
	}

	public void putSealed()
	{
		putHeaderIfItDoesNotExist(SEALED, "false");
	}

	public void putClassPath(final @NotNull Set<AbsoluteFile> zipOrJarFiles)
	{
		if (zipOrJarFiles.isEmpty())
		{
			return;
		}
		final StringWriter writer = new StringWriter();
		boolean afterFirst = false;
		for (AbsoluteFile absoluteFile : zipOrJarFiles)
		{
			if (afterFirst)
			{
				writer.write(" ");
			}
			afterFirst = true;
			absoluteFile.fileName().write(writer);
		}
		putHeaderIfItDoesNotExist(CLASS_PATH, writer.toString());
	}

	public void putMainClassName(final @NotNull String mainClassName)
	{
		if (mainClassName.isEmpty())
		{
			return;
		}
		putHeaderIfItDoesNotExist(MAIN_CLASS, mainClassName);
	}

	public void putSha1Digests(final @NotNull Set<ZipEntryAndData> zipEntries)
	{
		final Sha1DigestManifestWriter sha1DigestManifestWriter = new Sha1DigestManifestWriter(manifest.getEntries());
		for (ZipEntryAndData zipEntry : zipEntries)
		{
			sha1DigestManifestWriter.writeSha1DigestToManifest(zipEntry, zipEntry.pathNameInsideZip());
		}
	}

	private void putHeaderIfItDoesNotExist(final Name headerName, final String value)
	{
		if (!mainAttributes.containsKey(headerName))
		{
			buildLog.writeMessage(AllDetails, format(UK, "Writing header '%1$s' with value '%2$s'", headerName, value));
			mainAttributes.put(headerName, value);
		}
	}

	@NotNull
	public static Manifest basicManifest(final @NotNull BuildLog buildLog, final @NotNull BuildEnvironment buildEnvironment)
	{
		final Manifest manifest = new Manifest();
		new ManifestAttributesManipulator(manifest, buildLog)
		{{
			ensureBasicAttributes(buildEnvironment);
		}};
		return manifest;
	}
}
